package top.songxs.gmall.seckill.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import top.songxs.gmall.cart.vo.UserAuthInfoVo;
import top.songxs.gmall.common.execption.GmallException;
import top.songxs.gmall.common.result.ResultCodeEnum;
import top.songxs.gmall.common.util.UserAuthUtil;
import top.songxs.gmall.seckill.biz.SeckillGoodsBizService;
import top.songxs.gmall.seckill.constant.SeckillContant;
import top.songxs.gmall.seckill.entity.SeckillGoods;
import top.songxs.gmall.seckill.mapper.SeckillGoodsMapper;
import top.songxs.gmall.seckill.service.SeckillGoodsService;
import top.songxs.gmall.seckill.task.CachePreHotTask;

import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @author 86176
 * @description 针对表【seckill_goods】的数据库操作Service实现
 * @createDate 2023-06-09 18:30:41
 */
@Service
public class SeckillGoodsServiceImpl extends ServiceImpl<SeckillGoodsMapper, SeckillGoods>
        implements SeckillGoodsService {

    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private SeckillGoodsBizService seckillGoodsBizService;

    @Override
    public List<SeckillGoods> cachePreHotTask(Date date) {
        return seckillGoodsMapper.cachePreHotTask(date);
    }

    @Override
    public List<SeckillGoods> findSeckillGoodsList() {
        //从本地缓存中去取
        ConcurrentHashMap<Long, SeckillGoods> localCache = CachePreHotTask.LOCAL_CACHE;
        Collection<SeckillGoods> values = localCache.values();
        if (values.size() > 0) {
            List<SeckillGoods> goods = values.stream().collect(Collectors.toList());
            return goods;
        }
        //取不到去redis缓存中去取
        String redisGoodsKey = this.buildRedisGoodsKey();
        List<Object> objects = redisTemplate.opsForHash().values(redisGoodsKey);
        if (objects.size() > 0) {
            List<SeckillGoods> goodsList = objects.stream().map(obj -> {
                String jsonString = obj.toString();
                SeckillGoods goods = JSON.parseObject(jsonString, SeckillGoods.class);
                return goods;
            }).collect(Collectors.toList());
            return goodsList;
        }
        //最后还取不到取去MySQL
        List<SeckillGoods> goods = this.cachePreHotTask(new Date());
        return goods;

    }

    //构建redis秒杀key
    @Override
    public String buildRedisGoodsKey() {
        String dateStr = DateUtil.format(new Date(), "yyyy-MM-dd");
        return SeckillContant.REDIS_SECKILL_GOODS_KEY_PREFIX + dateStr;
    }

    //获取秒杀码的业务
    @Override
    public String getSeckillCode(Long skuId) {
        SeckillGoods seckillGoods = seckillGoodsBizService.findSeckillGoodsBySkuId(skuId);
        Date currentDate = new Date();
        Date startTime = seckillGoods.getStartTime();
        Date endTime = seckillGoods.getEndTime();
        //判断当前时间是否到达秒杀时间
        if (currentDate.getTime() > endTime.getTime()) {
            throw new GmallException(ResultCodeEnum.SECKILL_END);
        }
        if (currentDate.getTime() < startTime.getTime()) {
            throw new GmallException(ResultCodeEnum.SECKILL_NO_START);
        }
        // 库存很多位置都会存在：本地缓存、Redis、数据库。如果本地缓存没有了，那库存肯定是没有的。
        if (seckillGoods.getStockCount() < 0) {
            throw new GmallException(ResultCodeEnum.SECKILL_FINISH);
        }
        // 获取当前登录的用户信息
        UserAuthInfoVo userAuthInfo = UserAuthUtil.getUserAuthInfo();
        String userId = userAuthInfo.getUserId();

        //生成秒杀码
        String dateStr = DateUtil.format(currentDate, "yyyy-MM-dd");
        return this.generateSeckillCode(dateStr,userId,seckillGoods.getSkuId());
    }

    //进入秒杀队列排队代码
    @Override
    public void seckillQueue(Long skuId, String skuIdStr) {
        //校验用户传过来的秒杀码是不是当天的秒杀码
        String dateStr = DateUtil.format(new Date(), "yyyy-MM-dd");
        String seckillCode = generateSeckillCode(dateStr, UserAuthUtil.getUserAuthInfo().getUserId(), skuId);
        if (!seckillCode.equals(skuIdStr)){
            throw new GmallException(ResultCodeEnum.SECKILL_ILLEGAL);
        }

        // 校验是否是通过正常流程生成了秒杀码，正常流程在Redis中肯定会存在该秒杀码
        // 校验秒杀活动是否开始
        // 校验秒杀活动是否结束
        // 校验商品是否存在库存
        // 发送秒杀订单消息到MQ中

    }

    //具体生成秒杀码的代码
    private String generateSeckillCode(String dateStr, String userId, Long skuId) {
        String code = dateStr+"-"+userId+"-"+skuId;
        return DigestUtils.md5DigestAsHex(code.getBytes());
    }

}




